#include "TokenStream.h"
#include "CalExcep.hpp"

using namespace std;

namespace cal
{

TokenStream::TokenStream(std::istream& is)
	: _is{ is }, _eof{ is.eof() }, _full{ false }, _buffer{ }
{}

bool TokenStream::eof() const
{
	return _eof;
}

Token TokenStream::get() 
{
	if (_full) {
		_full = false;
		return _buffer;
	}
	Token token;
	if (_eof) return token;
	while (true) {
		char c = _is.peek();
		if (_is.eof()) {
			_eof = true;
			return Token{};
		}
		switch (c) {
			case ' ': 
			{
				_is.get();
				continue;
			}
			case '0': case '1': case '2': case '3': case '4': case '5': 
			case '6': case '7': case '8': case '9': case '.':
			{
				header::Number num;
				_is >> num;
				if (_is.fail()) throw CalExcep{"illegal number"};
				token.kind = Token::tk_number;
				token.val  = num;
				return token;
			}
			case globe::ADD: case globe::SUB: case globe::MUL: case globe::DIV: case globe::MOD: 
			case globe::POW: case globe::LBRA: case globe::RBRA: case globe::QUIT:
			{
				token.kind = _is.get();
				return token;
			}
			default: 
				throw CalExcep{ "illegal terminal character: '" + std::string{c} + "'" };
		}
	}
	return token;
}

Token TokenStream::peek() 
{
	if (!_full) {
		_buffer = get();
		_full = true;
	}
	return _buffer;
}

}   // namespace cal
